package de.dis2011.core;

import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import de.dis2011.data.Haus;
import de.dis2011.data.Immobilie;
import de.dis2011.data.Kaufvertrag;
import de.dis2011.data.Makler;
import de.dis2011.data.Mietvertrag;
import de.dis2011.data.Person;
import de.dis2011.data.Wohnung;

/**
 * Klasse zur Verwaltung aller Datenbank-Entitäten.
 * 
 * TODO: Aktuell werden alle Daten im Speicher gehalten. Ziel der Übung
 * ist es, schrittweise die Datenverwaltung in die Datenbank auszulagern.
 * Wenn die Arbeit erledigt ist, werden alle Sets dieser Klasse überflüssig.
 */
public class ImmoService {
	//Datensätze im Speicher
	//private Set<Makler> makler = new HashSet<Makler>();
	//private Set<Person> personen = new HashSet<Person>();
	//private Set<Haus> haeuser = new HashSet<Haus>();
	//private Set<Wohnung> wohnungen = new HashSet<Wohnung>();
	private Set<Mietvertrag> mietvertraege = new HashSet<Mietvertrag>();
	private Set<Kaufvertrag> kaufvertraege = new HashSet<Kaufvertrag>();
	
	//Hibernate Session
	private SessionFactory sessionFactory;
	
	public ImmoService() {
		sessionFactory = new Configuration().configure().buildSessionFactory();
	}
	
	/**
	 * Finde einen Makler mit gegebener Id
	 * @param id Die ID des Maklers
	 * @return Makler mit der ID oder null
	 */
	public Makler getMaklerById(int id) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		Makler makler_neu = new Makler();
		makler_neu = (Makler) session.get(Makler.class, id);
		session.getTransaction().commit();
		return makler_neu;
	}
	
	/**
	 * Finde einen Makler mit gegebenem Login
	 * @param login Der Login des Maklers
	 * @return Makler mit der ID oder null
	 */
	public Makler getMaklerByLogin(String login) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		Makler makler_neu = new Makler();
		makler_neu = (Makler) session.createQuery("from Makler as  makler where login = ?").setString(0,login).uniqueResult();
		session.getTransaction().commit();
		return makler_neu;
		
		/**Iterator<Makler> it = makler.iterator();
		
		while(it.hasNext()) {
			Makler m = it.next();
			
			if(m.getLogin().equals(login))
				return m;
		}
		
		return null;*/
	}
	
	/**
	 * Gibt alle Makler zurück
	 */
	public List<Makler> getAllMakler() {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		List<Makler> alleMakler = session.createQuery("from Makler as  makler").list();
		session.getTransaction().commit();
		return alleMakler;
	}
	
	/**
	 * Finde eine Person mit gegebener Id
	 * @param id Die ID der Person
	 * @return Person mit der ID oder null
	 */
	public Person getPersonById(int id) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		Person person_neu = new Person();
		person_neu = (Person) session.get(Person.class, id);
		session.getTransaction().commit();
		return person_neu;	
	}
	
	/**
	 * Fügt einen Makler hinzu
	 * @param m Der Makler
	 */
	public void addMakler(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.save(m);
		session.getTransaction().commit();
	}

	/**
	 * Ändert einen Makler 
	 * @param m Der Makler
	 */
	public void updateMakler(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.update(m);
		session.getTransaction().commit();
	}
	
	/**
	 * Löscht einen Makler
	 * @param m Der Makler
	 */
	public void deleteMakler(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.delete(m);
		session.getTransaction().commit();
	}
	
	/**
	 * Fügt eine Person hinzu
	 * @param p Die Person
	 */
	public void addPerson(Person p) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.save(p);
		session.getTransaction().commit();
	}
	
	/**
	 * Ändert einen Person 
	 * @param m die Person
	 */
	public void updatePerson(Person p) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.update(p);
		session.getTransaction().commit();
	}
	
	/**
	 * Gibt alle Personen zurück
	 */
	public List<Person> getAllPersons() {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		List<Person> allePersonen = session.createQuery("from Person as  person").list();
		session.getTransaction().commit();
		return allePersonen;
	}
	
	/**
	 * Löscht eine Person
	 * @param p Die Person
	 */
	public void deletePerson(Person p) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.delete(p);
		session.getTransaction().commit();
	}
	
	/**
	 * Fügt ein Haus hinzu
	 * @param h Das Haus
	 */
	public void addHaus(Haus h) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.save(h);
		session.getTransaction().commit();
	}
	
	/**
	 * Ändert ein Haus 
	 * @param h das Haus
	 */
	public void updateHaus(Haus h) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.update(h);
		session.getTransaction().commit();
	}
	
	/**
	 * Gibt alle Häuser eines Maklers zurück
	 * @param m Der Makler
	 * @return Alle Häuser, die vom Makler verwaltet werden
	 */
	public List<Haus> getAllHaeuserForMakler(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		List<Haus> alleHaeuser = session.createQuery("from Haus as  haus where verwalter =?").setEntity(0,m).list();
		session.getTransaction().commit();
		return alleHaeuser;
	}
	
	/**
	 * Findet ein Haus mit gegebener ID
	 * @param m Der Makler
	 * @return Das Haus oder null, falls nicht gefunden
	 */
	public Haus getHausById(int id) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		Haus haus_neu = new Haus();
		haus_neu = (Haus) session.get(Haus.class, id);
		session.getTransaction().commit();
		return haus_neu;	
	}
	
	/**
	 * Löscht ein Haus
	 * @param p Das Haus
	 */
	public void deleteHouse(Haus h) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.delete(h);
		session.getTransaction().commit();
	}
	
	/**
	 * Fügt eine Wohnung hinzu
	 * @param w die Wohnung
	 */
	public void addWohnung(Wohnung w) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.save(w);
		session.getTransaction().commit();
	}
	
	/**
	 * Fügt eine Wohnung hinzu
	 * @param w die Wohnung
	 */
	public void updateWohnung(Wohnung w) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.update(w);
		session.getTransaction().commit();
	}
	
	
	/**
	 * Gibt alle Wohnungen eines Maklers zurück
	 * @param m Der Makler
	 * @return Alle Wohnungen, die vom Makler verwaltet werden
	 */
	public List<Wohnung> getAllWohnungenForMakler(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		List<Wohnung> alleWohnungen = session.createQuery("from Wohnung as  wohnung where verwalter =?").setEntity(0,m).list();
		session.getTransaction().commit();
		return alleWohnungen;
	}
	
	/**
	 * Findet eine Wohnung mit gegebener ID
	 * @param id Die ID
	 * @return Die Wohnung oder null, falls nicht gefunden
	 */
	public Wohnung getWohnungById(int id) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		Wohnung wohnung_neu = new Wohnung();
		wohnung_neu = (Wohnung) session.get(Wohnung.class, id);
		session.getTransaction().commit();
		return wohnung_neu;	
	}
	
	/**
	 * Löscht eine Wohnung
	 * @param p Die Wohnung
	 */
	public void deleteWohnung(Wohnung w) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.delete(w);
		session.getTransaction().commit();
	}
	
	
	/**
	 * Fügt einen Mietvertrag hinzu
	 * @param w Der Mietvertrag
	 */
	public void addMietvertrag(Mietvertrag m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.save(m);
		session.getTransaction().commit();
	}
	
	/**
	 * ändert einen Mietvertrag
	 * @param w Der Mietvertrag
	 */
	public void updateMietvertrag(Mietvertrag m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.update(m);
		session.getTransaction().commit();
	}
	
	/**
	 * Fügt einen Kaufvertrag hinzu
	 * @param w Der Kaufvertrag
	 */
	public void addKaufvertrag(Kaufvertrag k) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.save(k);
		session.getTransaction().commit();
	}
	
	/**
	 * ändert einen Kaufvertrag
	 * @param w Der Kaufvertrag
	 */
	public void updateKaufvertrag(Kaufvertrag k) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.update(k);
		session.getTransaction().commit();
	}
	
	/**
	 * Gibt alle Mietverträge zu Wohnungen eines Maklers zurück
	 * @param m Der Makler
	 * @return Alle Mietverträge, die zu Wohnungen gehören, die vom Makler verwaltet werden
	 */
	public Set<Mietvertrag> getAllMietvertraegeForMakler(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		org.hibernate.Query q = session.createQuery("from Mietvertrag as mv where mv.wohnung in (Select distinct id from Wohnung where verwalter = ? )").setEntity(0,m);
		Iterator<Mietvertrag> it = q.iterate();
		mietvertraege.clear();
		while(it.hasNext()) {
			mietvertraege.add(it.next());
		}
		return mietvertraege;
	}
	
	/**
	 * Gibt alle Kaufverträge zu Wohnungen eines Maklers zurück
	 * @param m Der Makler
	 * @return Alle Kaufverträge, die zu Häusern gehören, die vom Makler verwaltet werden
	 */
	public Set<Kaufvertrag> getAllKaufvertraegeForMakler(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		org.hibernate.Query q = session.createQuery("from Kaufvertrag as kv where kv.haus in (Select distinct id from Haus where verwalter = ? )").setEntity(0,m);
		Iterator<Kaufvertrag> it = q.iterate();
		kaufvertraege.clear();
		while(it.hasNext()) {
			kaufvertraege.add(it.next());
		}
		return kaufvertraege;
	}
	
	/**
	 * Findet einen Mietvertrag mit gegebener ID
	 * @param id Die ID
	 * @return Der Mietvertrag oder null, falls nicht gefunden
	 */
	public Mietvertrag getMietvertragById(int id) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		Mietvertrag mietvertrag_neu = new Mietvertrag();
		mietvertrag_neu = (Mietvertrag) session.get(Mietvertrag.class, id);
		session.getTransaction().commit();
		return mietvertrag_neu;	
	}
	
	/**
	 * Findet alle Mietverträge, die Wohnungen eines gegebenen Verwalters betreffen
	 * @param id Der Verwalter
	 * @return Set aus Mietverträgen
	 */
	public List<Mietvertrag> getMietvertragByVerwalter(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		List<Mietvertrag> alleMietvertraege = session.createQuery("from Mietvertrag as mv, Wohnung as w where w.id = mv.wohnungsnr and w.verwalter = ?").setEntity(0,m).list();
		session.getTransaction().commit();
		return alleMietvertraege;
	}
	
	/**
	 * Findet alle Kaufverträge, die Häuser eines gegebenen Verwalters betreffen
	 * @param id Der Verwalter
	 * @return Set aus Kaufverträgen
	 */
	public List<Kaufvertrag> getKaufvertragByVerwalter(Makler m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		List<Kaufvertrag> alleKaufvertraege = session.createQuery("from Kaufvertrag as kv, Haus as h where h.id = kv.wohnungsnr and h.verwalter = ?").setEntity(0,m).list();
		session.getTransaction().commit();
		return alleKaufvertraege;
	}
	
	/**
	 * Findet einen Kaufvertrag mit gegebener ID
	 * @param id Die ID
	 * @return Der Kaufvertrag oder null, falls nicht gefunden
	 */
	public Kaufvertrag getKaufvertragById(int id) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		Kaufvertrag kaufvertrag_neu = new Kaufvertrag();
		kaufvertrag_neu = (Kaufvertrag) session.get(Kaufvertrag.class, id);
		session.getTransaction().commit();
		return kaufvertrag_neu;	
	}
	
	/**
	 * Löscht einen Mietvertrag
	 * @param m Der Mietvertrag
	 */
	public void deleteMietvertrag(Mietvertrag m) {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();
		session.delete(m);
		session.getTransaction().commit();
	}
	
	/**
	 * Fügt einige Testdaten hinzu
	 */
	public void addTestData() {
		//Hibernate Session erzeugen
		Session session = sessionFactory.openSession();
		
		Makler m = new Makler();
		m.setName("Max Mustermann");
		m.setAdresse("Am Informatikum 9");
		m.setLogin("max");
		m.setPasswort("max");
		this.addMakler(m);
		
		session.flush();
		//p1 refreshen
		session.refresh(m);
		
		Makler m2 = new Makler();
		m2.setName("seb");
		m2.setAdresse("seb");
		m2.setLogin("seb");
		m2.setPasswort("seb");
		this.addMakler(m2);
		
		session.flush();
		//p1 refreshen
		session.refresh(m2);
		
		Person p1 = new Person();
		p1.setAdresse("Informatikum");
		p1.setNachname("Mustermann");
		p1.setVorname("Erika");
		this.addPerson(p1);
				
		Person p2 = new Person();
		p2.setAdresse("Reeperbahn 9");
		p2.setNachname("Albers");
		p2.setVorname("Hans");
		this.addPerson(p2);
		
		Haus h = new Haus();
		h.setOrt("Hamburg");
		h.setPlz(22527);
		h.setStrasse("Vogt-Kölln-Straße");
		h.setHausnummer("2a");
		h.setFlaeche(384);
		h.setStockwerke(5);
		h.setKaufpreis(10000000);
		h.setGarten(true);
		h.setVerwalter(m);
		this.addHaus(h);
		
		//h refreshen
		session.refresh(h);
		
		Makler m3 = (Makler)session.get(Makler.class, m.getId());
		Set<Immobilie> immos = m.getImmobilien();
		Iterator<Immobilie> it = immos.iterator();
		
		while(it.hasNext()) {
			Immobilie i = it.next();
			System.out.println("Immo: "+i.getOrt());
		}
		
		
		Wohnung w = new Wohnung();
		w.setOrt("Hamburg");
		w.setPlz(22527);
		w.setStrasse("Vogt-Kölln-Straße");
		w.setHausnummer("3");
		w.setFlaeche(120);
		w.setStockwerk(4);
		w.setMietpreis(790);
		w.setEbk(true);
		w.setBalkon(false);
		w.setVerwalter(m);
		this.addWohnung(w);
		
		session.flush();
		session.refresh(w);
		
		Wohnung w2 = new Wohnung();
		w2.setOrt("Berlin");
		w2.setPlz(22527);
		w2.setStrasse("Vogt-Kölln-Straße");
		w2.setHausnummer("3");
		w2.setFlaeche(120);
		w2.setStockwerk(4);
		w2.setMietpreis(790);
		w2.setEbk(true);
		w2.setBalkon(false);
		w2.setVerwalter(m);
		this.addWohnung(w2);
		
		session.flush();
		session.refresh(w2);
		//p1 refreshen
		session.refresh(p1);
				
		Kaufvertrag kv = new Kaufvertrag();
		kv.setHaus(h);
		kv.setVertragspartner(p1);
		kv.setVertragsnummer(9234);
		kv.setDatum(new Date(System.currentTimeMillis()-1000000000));
		kv.setOrt("Hamburg");
		kv.setAnzahlRaten(5);
		kv.setRatenzins(4);
		this.addKaufvertrag(kv);

		//p2 refreshen
		session.refresh(p2);
		
		Mietvertrag mv = new Mietvertrag();
		mv.setWohnung(w);
		mv.setVertragspartner(p2);
		mv.setVertragsnummer(23112);
		mv.setDatum(new Date(System.currentTimeMillis()-1000000000));
		mv.setOrt("Berlin");
		mv.setMietbeginn(new Date(System.currentTimeMillis()));
		mv.setNebenkosten(65);
		mv.setDauer(36);
		this.addMietvertrag(mv);
		
		session.close();
	}
}
